Import xml
Import cal3d



Class SKNCalImageLoader Extends CalLoader
	
	
	Method Load:Object(data:String)
		Local isimvu:Bool = False

		Local error:= New XMLError
		Local doc:XMLDoc = ParseXML(data,error)
		If doc = Null And error.error
			Print error.ToString()
			loaded = True
			Return Null
		Endif
		
		Local imageElem:XMLNode = XMLNode(doc)
	
		If imageElem = Null Then 
			Print "Image Node not found!"
			loaded = True
			Return Null
		Endif		
		If imageElem.name <> "image" Then
			Print "Wrong Start Node: "+imageElem.name
			loaded = True
			Return Null				
		Endif	 
		#If( TARGET = "flash" )
			Local cimg:CalImage = New CalImage(Int(imageElem.GetXMLAttribute("width").value),Int(imageElem.GetXMLAttribute("height").value),mysplit(imageElem.value,"|"))
		#Else
			Local cimg:CalImage = New CalImage(Int(imageElem.GetXMLAttribute("width").value),Int(imageElem.GetXMLAttribute("height").value),imageElem.value.Split("|"))
		#Endif
		
		loadedobject = Object(cimg)
		loaded = True
		Return loadedobject			
		
	End	
		
End Class		


Class SKNCalMaterialLoader Extends CalLoader

	Method Load:Object(data:String)
		Local isimvu:Bool = False

		Local error:= New XMLError
		Local doc:XMLDoc = ParseXML(data,error)
		If doc = Null And error.error
			Print error.ToString()
			loaded = True
			Return Null
		Endif
		
		Local materialElem:XMLNode = XMLNode(doc)
		
		If materialElem = Null Then 
			Print "Material Node not found!"
			loaded = True
			Return Null
		Endif
		
		If materialElem.name <> "material" Then
			If materialElem.name = "header" Then
				materialElem = materialElem.GetChild()
				isimvu = True
				If materialElem.name <> "material" Then
					Print "Wrong Start Node: "+materialElem.name
					loaded = True
					Return Null				
				endif
			Else
				Print "Wrong Start Node: "+materialElem.name
				loaded = True
				Return Null	
			Endif
		Endif	
		
		Local coreMaterial:CalCoreMaterial = New CalCoreMaterial
		
		Local ambientElem:XMLNode = materialElem.GetChild("ambient")
		Local acol:String[] = ambientElem.value.Split(" ")
		Local ambientColor:CalColor = New CalColor(Int(acol[0]),Int(acol[1]),Int(acol[2]),Int(acol[3]))

		Local diffuseElem:XMLNode = materialElem.GetChild("diffuse")
		Local dcol:String[] = diffuseElem.value.Split(" ")
		Local diffuseColor:CalColor = New CalColor(Int(dcol[0]),Int(dcol[1]),Int(dcol[2]),Int(dcol[3]))

		Local specularElem:XMLNode = materialElem.GetChild("specular")
		Local scol:String[] = specularElem.value.Split(" ")
		Local specularColor:CalColor = New CalColor(Int(scol[0]),Int(scol[1]),Int(scol[2]),Int(scol[3]))
		
		Local shininessElem:XMLNode = materialElem.GetChild("shininess")
		
		Local shininess:Float = Float(shininessElem.value)
		coreMaterial.setAmbientColor(ambientColor)
		coreMaterial.setDiffuseColor(diffuseColor)
		coreMaterial.setSpecularColor(specularColor)
		coreMaterial.setShininess(shininess)
		
		Local MapIds:List<XMLNode> = materialElem.GetChildren("map")
		coreMaterial.reserve(MapIds.Count)
		Local mapId:Int = 0
		For Local mapElem:XMLNode = Eachin MapIds
			Local map:CalMap = New CalMap
			map.filename = mapElem.value
			coreMaterial.setMap(mapId, map)
			mapId = mapId + 1
		Next
		
		loadedobject = Object(coreMaterial)
		loaded = True
		Return loadedobject	
			
	End	
	

End Class



Class SKNCalAnimationLoader Extends CalLoader
	
	Field skel:CalCoreSkeleton
	
	
	Method Load:Object(data:String)
		Local isimvu:Bool = False

		Local error:= New XMLError
		Local doc:XMLDoc = ParseXML(data,error)
		If doc = Null And error.error
			Print error.ToString()
			loaded = True
			Return Null
		Endif
		
		Local animationElem:XMLNode = XMLNode(doc)
		
		If animationElem = Null Then 
			Print "Animation Node not found!"
			loaded = True
			Return Null
		Endif	
			
		If animationElem.name <> "animation" Then
			If animationElem.name = "header" Then
				animationElem = animationElem.GetChild()
				isimvu = True
				If animationElem.name <> "animation" Then
					Print "Wrong Start Node: "+animationElem.name
					loaded = True
					Return Null				
				endif
			Else
				Print "Wrong Start Node: "+animationElem.name
				loaded = True
				Return Null	
			Endif
		Endif	
		
		
		If animationElem.GetXMLAttribute("version").value <> "1000" And isimvu = False Then
			Print "Wrong Version: "+animationElem.GetXMLAttribute("version").value
			Return Null
		Endif
		
		Local duration:Float = Float(animationElem.GetXMLAttribute("duration").value)
		Local trackCount:Int = Int(animationElem.GetXMLAttribute("numtracks").value)
		
		Local coreAnimation:CalCoreAnimation = New CalCoreAnimation
		
		If duration <=0 Then
			Print "Invalid Duration"
			Return Null
		Endif
		
		coreAnimation.setDuration(duration)
		Local trackIds:List<XMLNode> = animationElem.GetChildren("track")
		
		For Local trackElem:XMLNode = Eachin trackIds
		
			Local coreTrack:CalCoreTrack = New CalCoreTrack
			
			Local coreBoneId:Int = Int(trackElem.GetXMLAttribute("boneid").value)
			coreTrack.setCoreBoneId(coreBoneId)
			
			Local keyframeCount:Int = Int(trackElem.GetXMLAttribute("numkeyframes").value)
			
			Local keyIds:List<XMLNode> = trackElem.GetChildren("keyframe")
		
			For Local keyframeElem:XMLNode = Eachin keyIds
			
				Local time:Float = Float(keyframeElem.GetXMLAttribute("time").value)
				
				Local translationElem:XMLNode = keyframeElem.GetChild("translation")
				Local tr:String[] = translationElem.value.Split(" ")
				Local tx:Float, ty:Float, tz:Float
				
				tx = Float(tr[0])
				ty = Float(tr[1])
				tz = Float(tr[2])
				Local trans:CalVector = New CalVector(tx, ty, tz)
				
				Local rotationElem:XMLNode = keyframeElem.GetChild("rotation")
				Local ro:String[] = rotationElem.value.Split(" ")
				Local rx:Float, ry:Float, rz:Float, rw:Float
				
				rx = Float(ro[0])
				ry = Float(ro[1])
				rz = Float(ro[2])
				rw = Float(ro[3])
				Local rot:CalQuaternion = New CalQuaternion(rx, ry, rz, rw)
				
				
				If skel <> null Then
				
					If skel.getCoreBone(coreBoneId).getParentId() = -1 then
				
						Local x_axis_90:CalQuaternion = New CalQuaternion(0.7071067811, 0, 0, 0.7071067811)
						rot.multQuaternionLocal(x_axis_90)
						trans.multQuaternionLocal(x_axis_90)
						
					endif
				Endif
				
				Local coreKeyframe:CalCoreKeyframe = New CalCoreKeyframe
				coreKeyframe.setTime(time)
				coreKeyframe.setTranslation(trans)
				coreKeyframe.setRotation(rot)
				coreTrack.addCoreKeyframe(coreKeyframe)
				
			Next
			coreAnimation.addCoreTrack(coreTrack)
		Next
		loadedobject = Object(coreAnimation)
		loaded = True
		Return loadedobject		
				
			
		
	End


End Class

Class SKNCalMeshLoader Extends CalLoader

	Method Load:Object(data:String)
		Local isimvu:Bool = false
		Local error:= New XMLError
		Local doc:XMLDoc = ParseXML(data,error)
		If doc = Null And error.error
			Print error.ToString()
			loaded = True
			Return Null
		Endif
		
		Local meshElem:XMLNode = XMLNode(doc)
		
		If meshElem = Null Then 
			Print "Mesh Node not found!"
			loaded = True
			Return Null
		Endif	
			
		If meshElem.name <> "mesh" Then
			If meshElem.name = "header" Then
				meshElem = meshElem.GetChild()
				isimvu = True
				If meshElem.name <> "mesh" Then
					Print "Wrong Start Node: "+meshElem.name
					loaded = True
					Return Null				
				endif
			Else
				Print "Wrong Start Node: "+meshElem.name
				loaded = True
				Return Null	
			Endif
		Endif
		
		'If meshElem.GetXMLAttribute("version").value <> "1000" And isimvu = False Then
		'	Print "Wrong Version: "+meshElem.GetXMLAttribute("version").value
		'	Return Null
		'Endif	
		
		Local submeshCount:Int = Int(meshElem.GetXMLAttribute("numsubmesh").value)	
		Local coreMesh:CalCoreMesh = New CalCoreMesh()
		
		Local submeshIds:List<XMLNode> = meshElem.GetChildren("submesh")
		
		For Local submeshElem:XMLNode = Eachin submeshIds
		
			Local coreMaterialThreadId:Int = Int(submeshElem.GetXMLAttribute("material").value)
			Local vertexCount:Int = Int(submeshElem.GetXMLAttribute("numvertices").value) 
			Local faceCount:Int = Int(submeshElem.GetXMLAttribute("numfaces").value)
			Local lodCount:Int = Int(submeshElem.GetXMLAttribute("numlodsteps").value)
			
			Local springCount:Int = 0
			If submeshElem.GetXMLAttribute("numsprings") <> Null then
				springCount = Int(submeshElem.GetXMLAttribute("numsprings").value)
			Endif
			Local textureCoordinateCount:Int = Int(submeshElem.GetXMLAttribute("numtexcoords").value)
			Local morphCount:Int = 0
			If submeshElem.GetXMLAttribute("nummorphs") <> Null then
				morphCount = Int(submeshElem.GetXMLAttribute("nummorphs").value)
			Endif
			Local coreSubmesh:CalCoreSubmesh = New CalCoreSubmesh()
			coreSubmesh.setLodCount(lodCount)
			coreSubmesh.setCoreMaterialThreadId(coreMaterialThreadId)
			
			If coreSubmesh.reserve(vertexCount, textureCoordinateCount, faceCount, springCount) = false Then
				Print "Could not reserve arrays"
				Return Null
			Endif
			
			Local vertIds:List<XMLNode> = submeshElem.GetChildren("vertex")
			Local vertexId:Int = 0
			For Local vertexElem:XMLNode = Eachin vertIds
			
				Local vertex:CalVertex = New CalVertex
				
				Local posElem:XMLNode = vertexElem.GetChild("pos")
				Local p:String[] = posElem.value.Split(" ")
				
				vertex.position.x = Float(p[0])
				vertex.position.y = Float(p[1])
				vertex.position.z = Float(p[2])
				
				Local normElem:XMLNode = vertexElem.GetChild("norm")
				Local n:String[] = normElem.value.Split(" ")
				
				vertex.normal.x = Float(n[0])
				vertex.normal.y = Float(n[1])
				vertex.normal.z = Float(n[2])				
				
				'skip collapse for the time being..
				Local textureCoordinateId:Int = 0
				Local textcoordsIds:List<XMLNode> = vertexElem.GetChildren("texcoord")
				For Local texcoordElem:XMLNode = Eachin textcoordsIds
				
					Local textureCoordinate:CalTextureCoordinate = New CalTextureCoordinate()
					Local tc:String[] = texcoordElem.value.Split(" ")
					
					textureCoordinate.u = Float(tc[0])
					textureCoordinate.v = Float(tc[1])
					
					coreSubmesh.setTextureCoordinate(vertexId, textureCoordinateId, textureCoordinate)
					textureCoordinateId = textureCoordinateId + 1
					
				Next
				Local influenceIds:List<XMLNode> = vertexElem.GetChildren("influence")
				Local influenceId:Int = 0
				For Local influenceElem:XMLNode = Eachin influenceIds
				
					Local influence:CalInfluence = New CalInfluence()
					influence.boneId = int(influenceElem.GetXMLAttribute("id").value)
					influence.weight = Float(influenceElem.value)
					vertex.vectorInfluence = vertex.vectorInfluence.Resize(vertex.vectorInfluence.Length+1)
					vertex.vectorInfluence[vertex.vectorInfluence.Length-1] = influence
					influenceId = influenceId + 1	
				Next				
				
				coreSubmesh.setVertex(vertexId, vertex)
				
				Local physIds:List<XMLNode> = vertexElem.GetChildren("physique")
				For Local physElem:XMLNode = Eachin physIds
				
					Local physicalProperty:CalPhysicalProperty = New CalPhysicalProperty
					physicalProperty.weight = Float(physElem.value)
					coreSubmesh.setPhysicalProperty(vertexId, physicalProperty)
				Next
				
				vertexId = vertexId + 1
			Next
			
			Local springIds:List<XMLNode> = submeshElem.GetChildren("spring")
			Local springId:Int = 0
			For Local springElem:XMLNode = Eachin springIds			
			
				Local spring:CalSpring = New CalSpring
				Local r:String[] = springElem.GetXMLAttribute("vertexid").value.Split(" ")
				
				spring.vertexId[0] = Int(r[0])
				spring.vertexId[1] = Int(r[1])
				spring.springCoefficient = Float(springElem.GetXMLAttribute("coef").value)
				spring.idleLength = Float(springElem.GetXMLAttribute("length").value)
				
				coreSubmesh.setSpring(springId, spring)
				springId = springId + 1
			Next


			Local morphIds:List<XMLNode> = submeshElem.GetChildren("morph")
			Local morphId:Int = 0
			For Local morphElem:XMLNode = Eachin morphIds		
				
				Local morphTarget:CalCoreSubMorphTarget = New CalCoreSubMorphTarget(morphElem.GetXMLAttribute("name").value)
				
				morphTarget.reserve(vertexCount)
				
				Local blendvertIds:List<XMLNode> = morphElem.GetChildren("blendvertex")
				
				For Local i:Int = 0 To vertexCount-1
					Local vertex:CalBlendVertex = New CalBlendVertex
					Local blendvertexId:Int = 0
					For Local blendvertexElem:XMLNode = Eachin blendvertIds				
					
						Local vid:Int = Int(blendvertexElem.GetXMLAttribute("vertexid").value)
						
						If vid = i Then
							
							Local posElem:XMLNode = blendvertexElem.GetChild("position")
							Local bp:String[] = posElem.value.Split(" ")
							
							vertex.position.x = Float(bp[0])
							vertex.position.y = Float(bp[1])
							vertex.position.z = Float(bp[2])
							
							Local normElem:XMLNode = blendvertexElem.GetChild("normal")
							Local bn:String[] = normElem.value.Split(" ")
							
							vertex.normal.x = Float(bn[0])
							vertex.normal.y = Float(bn[1])
							vertex.normal.z = Float(bn[2])								
							
							morphTarget.setBlendVertex(blendvertexId, vertex)
						Endif
					
					
						blendvertexId = blendvertexId + 1
					Next
				
				Next
				coreSubmesh.addCoreSubMorphTarget(morphTarget)
				morphId = morphId + 1
			Next
			
			Local faceId:Int = 0
			Local faceIds:List<XMLNode> = submeshElem.GetChildren("face")
			For Local faceElem:XMLNode = Eachin faceIds
			
				Local face:CalFace = New CalFace()
				Local fi:String[] = faceElem.GetXMLAttribute("vertexid").value.Split(" ")
				face.vertexId[0] = Int(fi[0])
				face.vertexId[1] = Int(fi[1])
				face.vertexId[2] = Int(fi[2])
				
				coreSubmesh.setFace(faceId, face)
				faceId = faceId + 1
			Next
			coreMesh.addCoreSubmesh(coreSubmesh)
		Next
			
		loadedobject = Object(coreMesh)
		loaded = True
		Return loadedobject		
	End

End Class

Class SKNCalSkeletonLoader Extends CalLoader

	Method Load:Object(data:String)
		Local isimvu:Bool = false
		Local error:= New XMLError
		Local doc:XMLDoc = ParseXML(data,error)
		If doc = Null And error.error
			Print error.ToString()
			loaded = True
			Return Null
		Endif
		
		Local skeletonElem:XMLNode = XMLNode(doc)' = doc.GetChild()
		
		If skeletonElem = Null Then 
			Print "Skeleton Node not found!"
			loaded = True
			Return Null
		Endif
		
		If skeletonElem.name <> "skeleton" Then
			If skeletonElem.name = "header" Then
				skeletonElem = skeletonElem.GetChild()
				isimvu = True
				If skeletonElem.name <> "skeleton" Then
					Print "Wrong Start Node: "+skeletonElem.name
					loaded = True
					Return Null				
				endif
			Else
				Print "Wrong Start Node: "+skeletonElem.name
				loaded = True
				Return Null	
			Endif
		Endif
		
		If skeletonElem.GetXMLAttribute("version").value <> "1000" And isimvu = False Then
			Print "Wrong Version: "+skeletonElem.GetXMLAttribute("version").value
			Return Null
		Endif
		
		Local coreSkeleton:CalCoreSkeleton = New CalCoreSkeleton()
		Local boneCount:Int = Int(skeletonElem.GetXMLAttribute("numbones").value)
		Local boneids:List<XMLNode> = skeletonElem.GetChildren("bone")
		'Local boneElem:XMLNode = skeletonElem.GetChild()
		'While boneElem <> Null
		For Local boneElem:XMLNode = Eachin boneids	
			Local name:String = boneElem.GetXMLAttribute("name").value
		
			Local translationElem:XMLNode = boneElem.GetChild("translation")
			If translationElem = Null Then
				Print "No Translation bone data"
				Return Null
			Endif
			
			Local r:String[] = translationElem.value.Split(" ")
			Local tx:Float,ty:Float,tz:Float
			tx = Float(r[0])
			ty = Float(r[1])
			tz = Float(r[2])
			
			Local rotationElem:XMLNode = boneElem.GetChild("rotation")
			If rotationElem = Null Then
				Print "No Rotation bone data"
				Return Null
			Endif
			
			Local rr:String[] = rotationElem.value.Split(" ") 
			Local rx:Float,ry:Float,rz:Float,rw:Float
			
			rx = Float(rr[0])
			ry = Float(rr[1])
			rz = Float(rr[2])
			rw = Float(rr[3])
			
			Local translationBoneSpaceElem:XMLNode = boneElem.GetChild("localtranslation")
			
			If translationBoneSpaceElem = Null Then
				Print "No Local Translation bone data"
				Return Null
			Endif
			
			
			Local txBoneSpace:Float, tyBoneSpace:Float, tzBoneSpace:Float
			Local tl:String[] = translationBoneSpaceElem.value.Split(" ")
			
			txBoneSpace = Float(tl[0])
			tyBoneSpace = Float(tl[1])
			tzBoneSpace = Float(tl[2])
			
			
			Local rotationBoneSpaceElem:XMLNode = boneElem.GetChild("localrotation")

			If rotationBoneSpaceElem = Null Then
				Print "No Local Rotation bone data"
				Return Null
			Endif
			
			Local lr:String[] = rotationBoneSpaceElem.value.Split(" ") 
			Local rxBoneSpace:Float, ryBoneSpace:Float, rzBoneSpace:Float, rwBoneSpace:Float
			
			rxBoneSpace = Float(lr[0])
			ryBoneSpace = Float(lr[1])
			rzBoneSpace = Float(lr[2])
			rwBoneSpace = Float(lr[3])
			
			Local parentElem:XMLNode = boneElem.GetChild("parentid")
			
			Local parentId:Int = Int(parentElem.value)
			
			
			
			
			Local coreBone:CalCoreBone = New CalCoreBone(name)
			coreBone.setParentId(parentId)
			
			
			
			
			Local trans:CalVector = New CalVector(tx, ty, tz)
			Local rot:CalQuaternion = New CalQuaternion(rx, ry, rz, rw)
			
			'Rotate Base Bone!
			If parentId = -1 Then
				Local x_axis_90:CalQuaternion = New CalQuaternion(0.7071067811, 0, 0, 0.7071067811)
				rot.multQuaternionLocal(x_axis_90)
				trans.multQuaternionLocal(x_axis_90)
			
			Endif
			
			coreBone.setTranslation(trans)
			coreBone.setRotation(rot)
			
			coreBone.setTranslationBoneSpace(New CalVector(txBoneSpace, tyBoneSpace, tzBoneSpace))
			coreBone.setRotationBoneSpace(New CalQuaternion(rxBoneSpace, ryBoneSpace, rzBoneSpace, rwBoneSpace))								
			
			Local childids:List<XMLNode> = boneElem.GetChildren("childid")
			For Local childElem:XMLNode = Eachin childids
			'Local childElem:XMLNode = boneElem.GetChild("childid")
			'While childElem <> Null
				
				Local childId:Int = Int(childElem.value)
				coreBone.addChildId(childId)
			
				'childElem = childElem.GetNextSibling("childid")
			Next
			coreBone.setCoreSkeleton(coreSkeleton)
			coreSkeleton.addCoreBone(coreBone)		
			'boneElem = boneElem.GetNextSibling("bone")
		'Wend
		Next
		coreSkeleton.calculateState()
		
		loadedobject = Object(coreSkeleton)
		loaded = True
		Return loadedobject
	End

End


Function mysplit:String[](mystring:String,ch:String)
 
	Local k:Int, s:Int, l:Int = mystring.Length
	Local part:String
	Local krs:Int[] = mystring.ToChars()
	Local res:StringList = New StringList
	s = 1
	For k = 1 To l
		
		If String.FromChar(krs[k-1]) = ch Then
			res.AddLast(part)
			part = ""
		Else
			part = part + String.FromChar(krs[k-1])
		Endif
	Next
	Return res.ToArray()
End